package com.zhoug.common.utils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

import java.util.Random;

import androidx.annotation.ColorInt;

/**
 * 图形验证码生成工具
 *
 * @Author 35574
 * @Date 2020/12/11
 * @Description
 */
public class ImageCodeGenerator {
    private static final String TAG = ">>>ImageCodeGenerator";
    private static final boolean DEBUG = false;

    private static final char[] CHARS = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };

    private StringBuilder mBuilder = new StringBuilder();
    private Random mRandom = new Random();

    //Default Settings
    private static final int DEFAULT_CODE_LENGTH = 4;//验证码的长度  这里是4位
    private static final int DEFAULT_LINE_NUMBER = 3;//多少条干扰线
    private static final int DEFAULT_WIDTH = 200;//默认宽度.图片的总宽
    private static final int DEFAULT_HEIGHT = 100;//默认高度.图片的总高
    private static final int DEFAULT_COLOR = 0XFFAAAAAA;//默认背景颜色值
    private static final int DEFAULT_PADDING = 20;//模式边距

    /**
     * 验证码长度
     */
    private int mCodeLength = DEFAULT_CODE_LENGTH;
    /**
     * 图片的宽
     */
    private int mBitmapWidth = DEFAULT_WIDTH;
    /**
     * 图片高
     */
    private int mBitmapHeight = DEFAULT_HEIGHT;
    /**
     * 图片背景色
     */
    private int mBackgroundColor = DEFAULT_COLOR;

    /**
     * 干扰线条数
     */
    private int mLineNumber = DEFAULT_LINE_NUMBER;

    /**
     * 字体大小
     */
    private float mFontSize;
    /**
     * 是否随机倾斜
     */
    private boolean mSkew = true;
    /**
     * 是否粗体
     * 优先级高于mRandomBold
     */
    private boolean mBold = true;
    /**
     * 是否随机粗体
     */
    private boolean mRandomBold = false;


    /**
     * 验证码字符串
     */
    private String code;

    private ImageCodeGenerator() {
    }

    public String getCode() {
        return code;
    }


    /**
     * 生成验证码图片
     *
     * @return
     */
    public Bitmap generate() {
        //生成的验证码
        code = generateCode();
        if (DEBUG) {
            LogUtils.d(TAG, "code:" + code);
        }
        Bitmap bitmap = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        //背景色
        canvas.drawColor(mBackgroundColor);
        if (DEBUG) {
            LogUtils.d(TAG, "mFontSize:" + mFontSize);
        }
        Paint paint = new Paint();
        paint.setTextSize(mFontSize);
        //空余的宽
        int widthSpace = (int) (mBitmapWidth - paint.measureText(code) - DEFAULT_PADDING * 2);
        int heightSpace = (int) (mBitmapHeight - mFontSize);
        float x = DEFAULT_PADDING; //每次生成验证码图片时初始化
        float y = 0;
        String c;
        int spaceX = 0;
        for (int i = 0; i < code.length(); i++) {
            randomTextStyle(paint);
            c = code.charAt(i) + "";
            spaceX = mRandom.nextInt(widthSpace);
            x += spaceX;
            widthSpace -= spaceX;
            y = mRandom.nextInt(heightSpace) + mFontSize;
            if (DEBUG) {
                LogUtils.d(TAG, "x:" + x + ",y:" + y);
            }
            canvas.drawText(c, x, y, paint);
            float w = paint.measureText(c);
            x += w;
        }
        //干扰线
        for (int i = 0; i < mLineNumber; i++) {
            drawLine(canvas, paint);
        }

        return bitmap;
    }

    /**
     * 计算文字大小
     *
     * @return
     */
    private void computeFontSize() {
        float size = ((mBitmapWidth - DEFAULT_PADDING * 2) * 3 / 5f) / mCodeLength * 2;
        size = Math.min(size, mBitmapHeight * 3 / 5f);
        mFontSize = size;
    }

    /**
     * 画干扰线
     *
     * @param canvas
     * @param paint
     */
    private void drawLine(Canvas canvas, Paint paint) {
        int color = randomColor();
        int startX = mRandom.nextInt(mBitmapWidth);
        int startY = mRandom.nextInt(mBitmapHeight);
        int stopX = mRandom.nextInt(mBitmapWidth);
        int stopY = mRandom.nextInt(mBitmapHeight);
        paint.setStrokeWidth(1);
        paint.setColor(color);
        canvas.drawLine(startX, startY, stopX, stopY, paint);
    }

    /**
     * 生成验证码
     *
     * @return
     */
    private String generateCode() {
        mBuilder.delete(0, mBuilder.length()); //使用之前首先清空内容
        int length = CHARS.length;
        for (int i = 0; i < mCodeLength; i++) {
            mBuilder.append(CHARS[mRandom.nextInt(length)]);
        }
        return mBuilder.toString();
    }


    /**
     * 随机颜色
     *
     * @return
     */
    private int randomColor() {
        mBuilder.delete(0, mBuilder.length()); //使用之前首先清空内容
        String haxString;
        for (int i = 0; i < 3; i++) {
            haxString = Integer.toHexString(mRandom.nextInt(0xFF));
            if (haxString.length() == 1) {
                haxString = "0" + haxString;
            }
            mBuilder.append(haxString);
        }
        return Color.parseColor("#" + mBuilder.toString());
    }

    /**
     * 随机文本样式
     *
     * @param paint
     */
    private void randomTextStyle(Paint paint) {
        int color = randomColor();
        paint.setColor(color);
        if (mBold) {
            paint.setFakeBoldText(true);
        } else if (mRandomBold) {
            paint.setFakeBoldText(mRandom.nextBoolean());  //true为粗体，false为非粗体
        }
        if (mSkew) {
            float skewX = mRandom.nextInt(7) / 10.0f + 0.4f;
            skewX = mRandom.nextBoolean() ? skewX : -skewX;
            paint.setTextSkewX(skewX); //float类型参数，负数表示右斜，整数左斜
        }

    }


    public static class Builder {

        /**
         * 验证码长度
         */
        private int mCodeLength = DEFAULT_CODE_LENGTH;
        /**
         * 图片的宽
         */
        private int mBitmapWidth = DEFAULT_WIDTH;
        /**
         * 图片高
         */
        private int mBitmapHeight = DEFAULT_HEIGHT;
        /**
         * 图片背景色
         */
        private int mBackgroundColor = DEFAULT_COLOR;

        /**
         * 干扰线条数
         */
        private int mLineNumber = DEFAULT_LINE_NUMBER;
        /**
         * 是否随机倾斜
         */
        private boolean mSkew = true;
        /**
         * 是否随机粗体
         */
        private boolean mBold = true;
        /**
         * 是否随机粗体
         */
        private boolean mRandomBold = false;

        /**
         * 设置验证码长度
         *
         * @param codeLength 默认值{@link #DEFAULT_CODE_LENGTH}
         * @return
         */
        public Builder setCodeLength(int codeLength) {
            if (codeLength > 0) {
                this.mCodeLength = codeLength;
            }
            return this;
        }

        /**
         * 设置验证码图片宽度
         *
         * @param bitmapWidth 默认值{@link #DEFAULT_WIDTH}
         * @return
         */
        public Builder setImageWidth(int bitmapWidth) {
            if (bitmapWidth > 0) {
                this.mBitmapWidth = bitmapWidth;
            }
            return this;
        }

        /**
         * 设置验证码图片高度
         *
         * @param bitmapHeight 默认值{@link #DEFAULT_HEIGHT}
         * @return
         */
        public Builder setImageHeight(int bitmapHeight) {
            if (bitmapHeight > 0) {
                this.mBitmapHeight = bitmapHeight;
            }
            return this;
        }

        /**
         * 设置验证码图片的背景色
         *
         * @param backgroundColor 默认值{@link #DEFAULT_COLOR}
         */
        public Builder setBackgroundColor(@ColorInt int backgroundColor) {
            this.mBackgroundColor = backgroundColor;
            return this;
        }

        /**
         * 设置验证码图片的干扰线条数
         *
         * @param lineNumber 默认值{@link #DEFAULT_LINE_NUMBER}
         */
        public Builder setLineNumber(int lineNumber) {
            if (lineNumber >= 0) {
                this.mLineNumber = lineNumber;
            }
            return this;
        }

        /**
         * 是否随机倾斜
         *
         * @param skew 默认 true
         * @return
         */
        public Builder setSkew(boolean skew) {
            this.mSkew = skew;
            return this;
        }

        /**
         * 是否粗体
         * @param bold 默认 true
         * @return
         */
        public Builder setBold(boolean bold) {
            this.mBold = bold;
            return this;
        }
        /**
         * 是否随机粗体
         *
         * @param randomBold 默认 false
         * @return
         */
        public Builder setRandomBold(boolean randomBold) {
            this.mRandomBold = randomBold;
            return this;
        }


        public ImageCodeGenerator build() {
            ImageCodeGenerator imageCodeGenerator = new ImageCodeGenerator();
            imageCodeGenerator.mCodeLength = mCodeLength;
            imageCodeGenerator.mBackgroundColor = mBackgroundColor;
            imageCodeGenerator.mBitmapHeight = mBitmapHeight;
            imageCodeGenerator.mLineNumber = mLineNumber;
            imageCodeGenerator.mSkew = mSkew;
            imageCodeGenerator.mBold = mBold;
            imageCodeGenerator.computeFontSize();
            return imageCodeGenerator;
        }

    }


}
